package top.guoziyang.mydb.backend.tm;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import top.guoziyang.mydb.backend.utils.Panic;
import top.guoziyang.mydb.common.Error;

public interface TransactionManager {
    long begin();
    void commit(long xid);
    void abort(long xid);
    boolean isActive(long xid);
    boolean isCommitted(long xid);
    boolean isAborted(long xid);
    void close();

    /**
     * 在 Java 8 及之后的版本中，接口类中可以定义静态方法，并且必须有方法体.
     * 因为静态方法与具体实现无关，所以不能在接口的实现类中重写静态方法。只能通过接口名直接调用。
     */
    // 创建xid文件并检查读写权限，并创建 TM
    public static TransactionManagerImpl create(String path) {
        File f = new File(path+TransactionManagerImpl.XID_SUFFIX);
        try {
            // 如果文件已经存在，使用Panic.panic()方法处理异常；如果文件不存在，创建成功。
            // Panic.panic()通常通过立即终止程序的方式来处理严重错误,一旦调用 panic()，程序会强制停止运行.
            if(!f.createNewFile()) {
                Panic.panic(Error.FileExistsException);
            }
        } catch (Exception e) {
            Panic.panic(e);
        }
        // 如果文件不可读或者不可写，则抛出自定义异常 FileCannotRWException
        if(!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }

        // RandomAccessFile 提供对文件的随机访问能力，即可以跳转到文件的任意位置进行读写操作.
        // 而 FileChannel 主要用于从文件中读取数据或写入数据，支持文件的部分读写,并且支持文件内存映射和锁定。
        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            // 使用 RandomAccessFile 以读写模式 (rw) 打开文件 f，并获得其 FileChannel，用于文件的随机读写操作。
            raf = new RandomAccessFile(f, "rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
           Panic.panic(e);
        }

        // 写空XID文件头，因为是新创建的xid文件
        ByteBuffer buf = ByteBuffer.wrap(new byte[TransactionManagerImpl.LEN_XID_HEADER_LENGTH]);
        try {
            // 将文件的指针移到文件文件的开始位置
            fc.position(0);
            // 将buf的内容写到文件中
            fc.write(buf);
        } catch (IOException e) {
            Panic.panic(e);
        }
        
        return new TransactionManagerImpl(raf, fc);
    }

    //从一个已有的 xid 文件来创建 TM
    public static TransactionManagerImpl open(String path) {
        File f = new File(path+TransactionManagerImpl.XID_SUFFIX);
        if(!f.exists()) {
            //如果文件不存在，处理FileNotExistsException异常
            Panic.panic(Error.FileNotExistsException);
        }
        if(!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }

        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(f, "rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
           Panic.panic(e);
        }

        return new TransactionManagerImpl(raf, fc);
    }
}
